﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq.Expressions;
using IDI.Studio.Core;

namespace IDI.Studio.Data
{
    public interface IRepository<TEntity> where TEntity : Entity
    {
        /// <summary>
        /// Gets the instance of the repository context on which the repository was attached.
        /// </summary>
        IRepositoryContext Context { get; }

        /// <summary>
        ///  Add an entity to current repository. 
        /// </summary>
        /// <param name="entity">The entity to be added.</param>
        void Add(TEntity entity);

        /// <summary>
        ///  Remove the entity from current repository. 
        /// </summary>
        /// <param name="entity">The entity to be removed.</param>
        void Remove(TEntity entity);

        /// <summary>
        ///  Update the entity from current repository. 
        /// </summary>
        /// <param name="entity">The entity to be updated.</param>
        void Update(TEntity entity);

        /// <summary>
        /// Gets the entity instance from repository by a given key.
        /// </summary>
        /// <param name="key">The key of the entity.</param>
        /// <returns>The instance of the entity.</returns>
        TEntity GetByKey(Guid key);

        /// <summary>
        /// Checkes whether the entity, which matches the given specification, exists in the repository.
        /// </summary>
        /// <param name="specification">The specification with which the entity should match.</param>
        /// <returns>True if the entity exists, otherwise false.</returns>
        bool Exists(ISpecification<TEntity> specification);

        /// <summary>
        /// Finds a single entity from the repository.
        /// </summary>
        /// <param name="specification">The specification with which the entity should match.</param>
        /// <returns>The instance of the entity.</returns>
        TEntity Find(ISpecification<TEntity> specification);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <returns>The entities.</returns>
        IEnumerable<TEntity> FindAll();

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <returns>The entities.</returns>
        IEnumerable<TEntity> FindAll(Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="pageNumber">The page number.</param>
        /// <param name="pageSize">The number of entities per page.</param>
        /// <returns>The entities.</returns>
        PagedResult<TEntity> FindAll(Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize);

        /// <summary>
        /// Finds all the entities that match the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <returns>The entities.</returns>
        IEnumerable<TEntity> FindAll(ISpecification<TEntity> specification);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <returns>The entities.</returns>
        IEnumerable<TEntity> FindAll(ISpecification<TEntity> specification, Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="pageNumber">The number of entities per page.</param>
        /// <param name="pageSize">The number of entities per page.</param>
        /// <returns>The entities.</returns>
        PagedResult<TEntity> FindAll(ISpecification<TEntity> specification, Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        IEnumerable<TEntity> FindAll(params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        IEnumerable<TEntity> FindAll(Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="pageNumber">The page number.</param>
        /// <param name="pageSize">The number of entities per page.</param>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        PagedResult<TEntity> FindAll(Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        IEnumerable<TEntity> FindAll(ISpecification<TEntity> specification, params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        IEnumerable<TEntity> FindAll(ISpecification<TEntity> specification, Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);

        /// <summary>
        /// Finds all the entities from repository.
        /// </summary>
        /// <param name="specification">The specification with which the entities should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param>
        /// <param name="pageNumber">The page number.</param>
        /// <param name="pageSize">The number of entities per page.</param>
        /// <param name="eagerLoadingProperties">The properties for the aggregated entities that need to be loaded.</param>
        /// <returns>The entity.</returns>
        PagedResult<TEntity> FindAll(ISpecification<TEntity> specification, Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params Expression<Func<TEntity, dynamic>>[] eagerLoadingProperties);
    }
}
